﻿using InTheHand.Net;
using InTheHand.Net.Bluetooth;
using InTheHand.Net.Sockets;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using MyTRCP.Common.Models;
using System.Net.Sockets;

namespace MyTRCP.Common.Services
{
    public abstract class DevBluetoothLinkService : BackgroundService
    {
        protected abstract Guid TargetService { get; }
        protected abstract string TargetServiceName { get; }
        private volatile AutoResetEvent _connectEvent;
        private volatile AutoResetEvent _connectedEvent;
        private volatile AutoResetEvent _disconnectEvent;
        private volatile AutoResetEvent _disconnectedEvent;
        private volatile AutoResetEvent _exceptionEvent;
        private volatile Exception? _excecption;
        private volatile BluetoothAddress? _btAddr;
        private volatile BluetoothClient? _btClient;
        private readonly ILogger<DevBluetoothLinkService> _logger;

        public event EventHandler? Connected;
        public event EventHandler? Disconnected;

        protected readonly Queue<byte> _btStreamReadUnprocessDataQueue;
        protected readonly BlockingQueue<byte[]> _btStreamReadCompletelyPayloadQueue;
        protected readonly BlockingQueue<byte[]> _btStreamWaitToWritePayloadQueue;
        private readonly bool _isLocalMode;
        public DevBluetoothLinkService(ILogger<DevBluetoothLinkService> logger, IConfigService ics)
        {
            _isLocalMode = true;
            _logger = logger;
            _connectEvent = new AutoResetEvent(false);
            _connectedEvent = new AutoResetEvent(false);
            _disconnectEvent = new AutoResetEvent(false);
            _disconnectedEvent = new AutoResetEvent(false);
            _exceptionEvent = new AutoResetEvent(false);
            _btStreamReadUnprocessDataQueue = new Queue<byte>();
            _btStreamReadCompletelyPayloadQueue = new BlockingQueue<byte[]>();
            _btStreamWaitToWritePayloadQueue = new BlockingQueue<byte[]>();
            if (ics is ClientConfigService ccs && ccs.ClientMode == ClientModeEnum.Remote)
            {
                _isLocalMode = false;
            }
        }
        public async Task<IReadOnlyCollection<BtDevInfo>?> DiscoverMyDevicesAsync(int maxDevs = 5)
        {
            try
            {
                return await Task.Run(() =>
                {
                    _logger.LogDebug($"开始发现蓝牙设备");
                    BluetoothClient bc = new BluetoothClient();
                    IReadOnlyCollection<BluetoothDeviceInfo> infos = bc.DiscoverDevices();
                    _logger.LogDebug($"系统发现{infos.Count}个设备，开始筛选");
                    List<BtDevInfo> devs = new List<BtDevInfo>();
                    foreach (BluetoothDeviceInfo info in infos)
                    {
                        if (devs.Count < maxDevs)
                        {
                            if (info.ClassOfDevice.Device == DeviceClass.AudioVideoHeadset || info.ClassOfDevice.Device == DeviceClass.AudioVideoHandsFree || info.ClassOfDevice.Device == DeviceClass.AudioVideoCar)
                            {
                                _logger.LogDebug($"筛选出目标设备，name:{info.DeviceName},mac:{info.DeviceAddress},device:{info.ClassOfDevice.Device},service:{info.ClassOfDevice.Service}");
                                devs.Add(new BtDevInfo(info.DeviceName, info.DeviceAddress));
                            }
                        }
                        else
                        {
                            _logger.LogDebug($"搜到数量已满{maxDevs}个，停止筛选");
                            break;
                        }
                    }
                    _logger.LogDebug($"结束。共筛选出{devs.Count}个设备");
                    return devs.AsReadOnly();
                });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"发现蓝牙设备时出现异常：{ex.Message}");
                return null;
            }
        }
        public bool IsConnected => _btClient?.Connected ?? false;
        public BlockingQueue<byte[]> PayloadRecvQueue => _btStreamReadCompletelyPayloadQueue;
        public BlockingQueue<byte[]> PayloadSendQueue => _btStreamWaitToWritePayloadQueue;
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            if (_isLocalMode)
            {
                _logger.LogDebug($"{TargetServiceName}服务启动，开始循环");
                await Task.Run(async () =>
                {
                    try
                    {
                        while (!stoppingToken.IsCancellationRequested)
                        {
                            try
                            {
                                _connectEvent.Reset();
                                _connectedEvent.Reset();
                                _disconnectEvent.Reset();
                                _disconnectedEvent.Reset();
                                if (WaitHandle.WaitAny([_connectEvent, stoppingToken.WaitHandle]) != 0)
                                {
                                    _logger.LogDebug($"{TargetServiceName}服务收到停止信号准备退出（未连接）");
                                    break;//exit
                                }
                                _logger.LogDebug($"{TargetServiceName}服务开始连接");
                                if (_btAddr == null)
                                {
                                    _logger.LogDebug($"{TargetServiceName}服务的蓝牙地址为空无法连接");
                                    continue;
                                }
                                _btClient = new BluetoothClient();
                                BluetoothSecurity.PairRequest(_btAddr, "1234");
                                _btClient.Connect(_btAddr, TargetService);
                                _logger.LogDebug($"{TargetServiceName}服务连接成功，启动发送接收线程");
                                Task recv = Task.Run(() => ReceivedMethod(stoppingToken), stoppingToken);
                                Task send = Task.Run(() => SendMethod(stoppingToken), stoppingToken);
                                _connectedEvent.Set();
                                Connected?.Invoke(this, EventArgs.Empty);
                                int r = WaitHandle.WaitAny([_disconnectEvent, stoppingToken.WaitHandle]);
                                _logger.LogDebug($"{TargetServiceName}服务收到停止信号准备退出（已连接）");
                                _btClient.Client.Shutdown(SocketShutdown.Both);
                                _btClient.Client.Disconnect(true);
                                _btClient.Close();
                                _btClient = null;
                                _btStreamWaitToWritePayloadQueue.CancelTake();
                                _disconnectedEvent.Set();
                                Disconnected?.Invoke(this, EventArgs.Empty);
                                await Task.WhenAll(recv, send);
                                _logger.LogDebug($"{TargetServiceName}服务发送接收线程已关闭");
                                if (r != 0)
                                {
                                    break;
                                }
                            }
                            catch (OperationCanceledException)
                            {
                                _logger.LogInformation($"{TargetServiceName}服务单次连接中收到退出指令，退出");
                                _connectEvent.Reset();
                                _connectedEvent.Reset();
                                _disconnectEvent.Reset();
                                _disconnectedEvent.Reset();
                                if (_btClient != null && _btClient.Connected)
                                {
                                    _btClient.Close();
                                    _btClient = null;
                                    _btStreamWaitToWritePayloadQueue.CancelTake();
                                    _logger.LogDebug($"{TargetServiceName}服务蓝牙链接已关闭");
                                }
                                break;
                            }
                            catch (Exception e)
                            {
                                _logger.LogError(e, $"{TargetServiceName}服务单次连接中出现异常");
                                _connectEvent.Reset();
                                _connectedEvent.Reset();
                                _disconnectEvent.Reset();
                                _disconnectedEvent.Reset();
                                _excecption = e;
                                _exceptionEvent.Set();
                                if (_btClient != null && _btClient.Connected)
                                {
                                    _btClient.Close();
                                    _btClient = null;
                                    _btStreamWaitToWritePayloadQueue.CancelTake();
                                    _logger.LogDebug($"{TargetServiceName}服务蓝牙链接已关闭");
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, $"{TargetServiceName}服务出现异常");
                    }
                }, stoppingToken);
                _logger.LogDebug($"{TargetServiceName}服务退出，结束循环");
            }
            else
            {
                _logger.LogInformation($"{TargetServiceName}服务非本地模式运行，退出");
            }
        }
        protected List<byte> uncompletePayload = new List<byte>();
        protected bool payloadRecvUncomplete = false;
        protected byte[] recvBuf = new byte[512];
        protected int readLen = 0;
        protected byte nowByte = 0;
        protected abstract void ProcessReceivedDataQueue();
        private void ReceivedMethod(CancellationToken stoppingToken)
        {
            _logger.LogDebug($"{TargetServiceName}服务接收线程开始循环");
            try
            {
                while (!stoppingToken.IsCancellationRequested)
                {
                    if (_btClient != null && _btClient.Connected)
                    {
                        try
                        {
                            readLen = _btClient.Client.Receive(recvBuf, 0, recvBuf.Length, SocketFlags.None);
                            if (readLen > 0)
                            {
                                for (int i = 0; i < readLen; i++)
                                {
                                    _btStreamReadUnprocessDataQueue.Enqueue(recvBuf[i]);
                                }
                                ProcessReceivedDataQueue();
                                _logger.LogTrace($"{TargetServiceName}服务收到数据：{Tools.BufferBytes2HexString(recvBuf, 0, readLen)}");
                            }
                        }
                        catch (OperationCanceledException)
                        {
                            _logger.LogInformation($"{TargetServiceName}服务接收线程收到退出指令，退出");
                            break;
                        }
                        catch (Exception e)
                        {
                            _logger.LogError(e, $"{TargetServiceName}服务接收线程循环内出现异常");
                            if (_btClient == null || (_btClient != null && !_btClient.Connected))
                            {
                                _disconnectEvent.Set();
                            }
                        }
                    }
                    else
                    {
                        _logger.LogInformation($"{TargetServiceName}服务接收线程检测到链接断开，退出");
                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"{TargetServiceName}服务接收线程出现异常");
            }
            _logger.LogDebug($"{TargetServiceName}服务接收线程结束循环");
        }
        private void SendMethod(CancellationToken stoppingToken)
        {
            _logger.LogDebug($"{TargetServiceName}服务发送线程开始循环");
            try
            {
                while (!stoppingToken.IsCancellationRequested)
                {
                    if (_btClient != null && _btClient.Connected)
                    {
                        try
                        {
                            byte[] payload = _btStreamWaitToWritePayloadQueue.Take();
                            _btClient.Client.Send(payload, SocketFlags.None);
                            _logger.LogTrace($"{TargetServiceName}服务发送数据：{Tools.ByteArray2HexString(payload)}");
                        }
                        catch (OperationCanceledException)
                        {
                            _logger.LogInformation($"{TargetServiceName}服务发送线程收到退出指令，退出");
                            break;
                        }
                        catch (Exception e)
                        {
                            _logger.LogError(e, $"{TargetServiceName}服务发送线程循环内出现异常");
                            if (_btClient == null || (_btClient != null && !_btClient.Connected))
                            {
                                _disconnectEvent.Set();
                            }
                        }
                    }
                    else
                    {
                        _logger.LogInformation($"{TargetServiceName}服务发送线程检测到链接断开，退出");
                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"{TargetServiceName}服务发送线程出现异常");
            }
            _btStreamWaitToWritePayloadQueue.Clear();
            _logger.LogDebug($"{TargetServiceName}服务发送线程结束循环");
        }
        public async Task<bool> OpenAsync(BluetoothAddress ba)
        {
            return await Task.Run(() =>
             {
                 if (_btClient == null || !_btClient.Connected)
                 {
                     _btAddr = ba;
                     _connectEvent.Set();
                     if (WaitHandle.WaitAny([_connectedEvent, _exceptionEvent]) == 0)
                     {
                         _logger.LogDebug($"{TargetServiceName}链路连接成功");
                         return true;
                     }
                     else
                     {
                         _logger.LogDebug($"{TargetServiceName}链路连接失败");
                         _connectedEvent.Reset();
                         return false;
                     }
                 }
                 _logger.LogDebug($"{TargetServiceName}链路已连接无需重复连接");
                 return false;
             });
        }
        public async Task<bool> CloseAsync()
        {
            return await Task.Run(() =>
            {
                if (_btClient != null && _btClient.Connected)
                {
                    _btAddr = null;
                    _disconnectEvent.Set();
                    if (WaitHandle.WaitAny([_disconnectedEvent, _exceptionEvent]) == 0)
                    {
                        _logger.LogDebug($"{TargetServiceName}链路断开成功");
                        return true;
                    }
                    else
                    {
                        _logger.LogDebug($"{TargetServiceName}链路断开失败");
                        _disconnectedEvent.Reset();
                        return false;
                    }
                }
                _logger.LogDebug($"{TargetServiceName}链路已断开无需重复断开");
                return false;
            });
        }
        public override Task StartAsync(CancellationToken cancellationToken)
        {
            _logger.LogDebug("startasync called");
            return base.StartAsync(cancellationToken);
        }
        public override async Task StopAsync(CancellationToken cancellationToken)
        {
            await CloseAsync();
            await base.StopAsync(cancellationToken);
        }
    }
}
